﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json;

namespace AIC_Notification
{
    public class AIC_Application
    {
        public string BoardName { get; set; }
        public string Id { get; set; }
        public string Url { get; set; }
        public string Note { get; set; }
        public string SortOrder = "";

        public string Name;
        public int ApplicationYear;
        public string Program;
        public string City;
        public string AC_PT;
        public string AC_ST;
        public string EC;

        [JsonIgnore]
        public Student StudentObject = null;

        public virtual void Reset()
        {
        }

        public virtual void CalculateStatistics()
        {
        }
    }

    public class Guidance_Application : AIC_Application
    {
        public Guidance_MonthlyPlanList MonthlyPlanList = null;
        public Guidance_MeetingRecapList MeetingRecapList = null;
        public Guidance_EvaluationReportCardList EvaluationReportCardList = null;

        public Guidance_Application(string boardName, string boardId, string boardUrl, int applicationYear, string program, string city, string studentName, string acPT, string acST, string ec)
        {
            // Record Trello Information 
            BoardName = boardName;
            Id = boardId;
            Url = boardUrl;
            Note = "";

            ApplicationYear = applicationYear;
            Program = program;
            City = city;
            Name = studentName;
            AC_PT = acPT;
            AC_ST = acST;
            EC = ec;

            // Global.SysUtil.Log(String.Format("Application Year: {0}, Program: {1}, City: {2}, Student: {3}, PT: {4}, ST: {5}, EC: {6}", ApplicationYear, Program, City, Name, AC_PT, AC_ST, EC));
        }
    }

    public class SOF_Application: AIC_Application
    {
        // Lists
        public IList<SOF_WorkList> Schools;
        public int NoOfEssayList = 0;
        public int NoOfTaskList = 0;

        static public int MAX_SCHOOL_IN_RALLY = 15;

        [JsonIgnore]
        public SOF_WorkList[][] RallyOfSchools;

        [JsonIgnore]
        public SOF_ApplicationStatistics ApplicationStats;

        public SOF_Application(string boardName, string boardId, string boardUrl, int applicationYear, string program, string city, string studentName, string acPT, string acST, string ec)
        {
            // Record Trello Information 
            BoardName = boardName;
            Id = boardId;
            Url = boardUrl;
            Note = "";

            ApplicationYear = applicationYear;
            Program = program;
            City = city;
            Name = studentName;
            AC_PT = acPT;
            AC_ST = acST;
            EC = ec;

            Reset();

            // Global.SysUtil.Log(String.Format("Application Year: {0}, Program: {1}, City: {2}, Student: {3}, PT: {4}, ST: {5}, EC: {6}", ApplicationYear, Program, City, Name, AC_PT, AC_ST, EC));
        }

        public override void Reset()
        {
            Schools = new List<SOF_WorkList>();

            RallyOfSchools = new SOF_WorkList[RallyHelper.NoOfRally + 1][]; // +1 because we have CEF as Rally 0
            for (int i = 0; i < RallyHelper.NoOfRally + 1; i++)
            {
                RallyOfSchools[i] = new SOF_WorkList[MAX_SCHOOL_IN_RALLY];
                for (int j = 0; j < MAX_SCHOOL_IN_RALLY; j++)
                {
                    RallyOfSchools[i][j] = null;
                }
            }
        }

        public void AddSchoolsToRally()
        {
            foreach (var School in Schools)
                AddSchoolToRally(School, School.Rally);
        }

        private void AddSchoolToRally(SOF_WorkList List, int Rally)
        {
            if (List.School == "CEF")
            {
                RallyOfSchools[0][0] = List;
            }
            else if (List.School == "PS")
            {
                RallyOfSchools[1][0] = List;

            }
            else if (List.School == "HAL")
            {
                RallyOfSchools[1][1] = List;
            }
            else
            {
                if (List.ListType == "School")
                {
                    // Check if Rally is valid
                    if (Rally >= 2 && Rally <= RallyHelper.NoOfRally)
                    {
                        bool TooManySchoolInRally = true; 

                        // Check if there are no more than 5 schools (and no more than 2 from Rally 2 to 7)
                        int SchoolNumber = 0;
                        for (int i = 0; i < MAX_SCHOOL_IN_RALLY; i++)
                        {
                            if (RallyOfSchools[Rally][i] == null)
                            {
                                TooManySchoolInRally = false;
                                SchoolNumber = i;
                                break;
                            }
                        }

                        // Valid Rally and School #
                        if (TooManySchoolInRally)
                            Global.SysUtil.Log(String.Format("Too many school in one Rally {0} ({1})", Rally, BoardName), 2);

                        // Insert School into Rally
                        RallyOfSchools[Rally][SchoolNumber] = List;
                    }
                    else
                    {
                        Global.InputErrors.Add(new Error(this, List, null, Error.Owner.ac, String.Format("Invalid Rally {0} in Board ({1})", Rally, BoardName)));

                    }
                }
            }
        }

        public void AddSchool(SOF_WorkList List, int Rally)
        {
            Schools.Add(List);

            // AddSchoolToRally(List, Rally);
        }

        public SOF_WorkList GetSchool(string School)
        {
            SOF_WorkList TargetSchool = Schools.FirstOrDefault(SOF_WorkList => SOF_WorkList.ListType.Equals(School));

            return TargetSchool;
        }

        public SOF_WorkList GetSchool(int Rally, int SchoolNumber)
        {
            if (Rally < 0 || Rally > RallyHelper.NoOfRally)
            {
                Global.SysUtil.Log(String.Format("Invalid Rally {0} in GetSchool", Rally), 2);
                return null;
            }

            if (SchoolNumber < 0 || SchoolNumber > MAX_SCHOOL_IN_RALLY)
            {
                Global.SysUtil.Log(String.Format("Invalid School # {0} in GetSchool", SchoolNumber), 2);
                return null;
            }

            return RallyOfSchools[Rally][SchoolNumber];
        }

        public int NoOfSchool()
        {
            int SchoolCount = 0;

            foreach (var school in Schools)
            {
                if (school.ListType == "School")
                    SchoolCount += 1;
            }

            return SchoolCount;
        }

        private void AddUCSchoolTypeStats(SOF_Application Application, School ApplyingSchool)
        {
            SchoolAdmissionStatistics.SchoolListType AI_SchoolType = Global.SysUtil.CalculateSchoolType(Application, ApplyingSchool);
            SchoolAdmissionStatistics.SchoolListType Consultant_SchoolType = Global.SysUtil.LookupAdmissionResultSchoolType(Application, ApplyingSchool);

            // If consultant info present, alawys use;  if not, fall back to AI.
            SchoolAdmissionStatistics.SchoolListType SchoolType = Consultant_SchoolType != SchoolAdmissionStatistics.SchoolListType.Unknown ? Consultant_SchoolType : AI_SchoolType;

            switch (SchoolType)
            {
                case SchoolAdmissionStatistics.SchoolListType.Unknown:
                    ApplicationStats.SchoolTypeStats.Unknown += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Safety:
                    ApplicationStats.SchoolTypeStats.UC_Safety += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Match:
                    ApplicationStats.SchoolTypeStats.UC_Match += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Reach:
                    ApplicationStats.SchoolTypeStats.UC_Reach += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.SuperReach:
                    ApplicationStats.SchoolTypeStats.UC_SuperReach += 1;
                    break;
                default:
                    break;
            }
        }

        private void AddSchoolAcceptedStats(SOF_Application Application, School ApplyingSchool)
        {
            // Sum up total Accepted
            if (Application != null && ApplyingSchool != null)
            {
                StudentAdmissionResult SchoolResult = null;

                if (Application.StudentObject != null)
                    SchoolResult = Application.StudentObject.FindAdmissionResult(ApplyingSchool);

                if (SchoolResult != null)
                {
                    if (SchoolResult.ApplicationResult == "Accept" || SchoolResult.ApplicationResult == "Defer Accept" || SchoolResult.ApplicationResult == "Waitlist Accept")
                    {
                        if (SchoolResult.Category == "Reach School")
                            ApplicationStats.SchoolTypeStats.ReachAccepted += 1;
                        else if (SchoolResult.Category == "Solid School")
                            ApplicationStats.SchoolTypeStats.SolidAccepted += 1;
                        else if (SchoolResult.Category == "Safety School")
                            ApplicationStats.SchoolTypeStats.SafetyAccepted += 1;
                    }
                }
            }
        }

        private void AddSchoolTypeStats(SOF_Application Application, SOF_WorkList ApplyingSchool)
        {
            SchoolAdmissionStatistics.SchoolListType AI_SchoolType = Global.SysUtil.CalculateSchoolType(Application, ApplyingSchool.SchoolObject);
            SchoolAdmissionStatistics.SchoolListType Consultant_SchoolType = Global.SysUtil.LookupAdmissionResultSchoolType(Application, ApplyingSchool.SchoolObject);

            // If consultant info present, alawys use;  if not, fall back to AI.
            SchoolAdmissionStatistics.SchoolListType SchoolType = Consultant_SchoolType != SchoolAdmissionStatistics.SchoolListType.Unknown ? Consultant_SchoolType : AI_SchoolType;

            switch (SchoolType)
            {
                case SchoolAdmissionStatistics.SchoolListType.Unknown:
                    ApplicationStats.SchoolTypeStats.Unknown += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Safety:
                    ApplicationStats.SchoolTypeStats.Safety += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Match:
                    ApplicationStats.SchoolTypeStats.Match += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.Reach:
                    ApplicationStats.SchoolTypeStats.Reach += 1;
                    break;
                case SchoolAdmissionStatistics.SchoolListType.SuperReach:
                    ApplicationStats.SchoolTypeStats.SuperReach += 1;
                    break;
                default:
                    break;
            }
        }

        private void CalculateSchoolTypeStatistics(SOF_Application Application, SOF_WorkList ApplyingSchool, SOF_ApplicationStatistics ApplicationStats)
        {
            if (ApplyingSchool != null && ApplyingSchool.ListType == "School")
            {
                if (ApplyingSchool.School.StartsWith("UC-", StringComparison.CurrentCultureIgnoreCase))
                {
                    ApplicationStats.SchoolTypeStats.SupplimentSchool += 1;

                    // Fill in school full name
                    string UCSubSchoolPattern = @"(?i:(B|D|I|LA|M|R|SD|SB|SC))";
                    string SubSchoolList = ApplyingSchool.School.Substring(3);

                    MatchCollection Subschools = Regex.Matches(SubSchoolList, UCSubSchoolPattern);

                    foreach (Match Subschool in Subschools)
                    {
                        School UC_School;

                        switch (Subschool.Value.ToLower())
                        {
                            case "b":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.B);
                                break;
                            case "d":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.D);
                                break;
                            case "i":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.I);
                                break;
                            case "la":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.LA);
                                break;
                            case "m":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.M);
                                break;
                            case "r":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.R);
                                break;
                            case "sd":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.SD);
                                break;
                            case "sb":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.SB);
                                break;
                            case "sc":
                                UC_School = SchoolDB.GetUCSchool(SchoolDB.UC.SC);
                                break;
                            default:
                                UC_School = null;
                                Global.InputErrors.Add(new Error(Application, ApplyingSchool, null, Error.Owner.ac, String.Format("Unknow UC School: {0} ", Subschool.Value)));
                                break;
                        }

                        if (UC_School != null)
                        {
                            AddUCSchoolTypeStats(Application, UC_School);
                            AddSchoolAcceptedStats(Application, UC_School);
                        }
                    }
                }
                else
                {
                    if (ApplyingSchool.School.Equals("UC", StringComparison.CurrentCultureIgnoreCase))
                    {
                        // Global.InputErrors.Add(new Error(Application, ApplyingSchool, null, Error.Owner.admin, String.Format("Missing UC Subschools")));
                        ApplicationStats.SchoolTypeStats.SupplimentSchool += 1;
                        ApplicationStats.SchoolTypeStats.Unknown += 1;
                    }
                    else
                    {
                        // Match school short name
                        School College = SchoolDB.GetSchoolbyShortName(ApplyingSchool.School);

                        if (College != null)
                        {
                            ApplyingSchool.SchoolObject = College;
                            ApplyingSchool.SchoolType = Global.SysUtil.CalculateSchoolType(Application, ApplyingSchool.SchoolObject);

                            // Update Suppliment Stats
                            ApplyingSchool.NonSuppliment = College.NonSuppliment() ||  ApplyingSchool.NonSuppliment;

                            if (ApplyingSchool.NonSuppliment)
                                ApplicationStats.SchoolTypeStats.NonSupplimentSchool += 1;
                            else
                                ApplicationStats.SchoolTypeStats.SupplimentSchool += 1;

                            // Update School Type Stats
                            AddSchoolTypeStats(Application, ApplyingSchool);
                        }

                        AddSchoolAcceptedStats(Application, ApplyingSchool.SchoolObject);

                        if ((College == null)) // Special case for UC
                            Global.InputErrors.Add(new Error(Application, ApplyingSchool, null, Error.Owner.ac, String.Format("No college short name: {0} ", ApplyingSchool.School)));
                    }
                }

                // Update School Essay Status 
                if (!ApplyingSchool.NonSuppliment)
                {
                    if (ApplyingSchool.SchoolStats.RallyStatus == 1)
                        ApplicationStats.SchoolEssayCompletionStats.CompletedSchools += 1;
                    else if (ApplyingSchool.SchoolStats.RallyStatus == 2)
                        ApplicationStats.SchoolEssayCompletionStats.InProgressSchools += 1;
                    else
                        ApplicationStats.SchoolEssayCompletionStats.BehindSchools += 1;
                }
            }
        }

        public override void CalculateStatistics()
        {
            ApplicationStats = new SOF_ApplicationStatistics();

            // Create Rally School Array
            AddSchoolsToRally();

            foreach (var School in Schools)
            {
                Global.ProcessingWorkList = School;

                // Calculate list statistics
                if (School.Essays.Count > 0)
                    School.CalculateStatistics();

                // Calculate school statistics
                CalculateSchoolTypeStatistics(this, School, ApplicationStats);

                ApplicationStats.NumberOfLateEssay += School.SchoolStats.NumberOfLateEssay;
            }

            if (StudentObject != null && StudentObject.ResultListObject != null)
            {
                foreach (var AdmissionResult in StudentObject.ResultListObject)
                {
                    bool FoundSchool = false;
                    bool HasUC = false;

                    // Has UC?
                    foreach (var School in Schools)
                    {
                        if (School.School == "UC" || School.School.StartsWith("UC-", StringComparison.CurrentCultureIgnoreCase))
                            HasUC = true;
                    }

                    if (SchoolDB.IsUCSchool(AdmissionResult.SchoolID))
                    {
                        if (HasUC)
                            FoundSchool = true;
                    }
                    else
                    {
                        foreach (var School in Schools)
                        {
                            if (School.SchoolObject != null && (AdmissionResult.SchoolID == School.SchoolObject.ID))
                                FoundSchool = true;
                        }
                    }

                    if (!FoundSchool)
                        if (Global.Now().Month >= 2 && Global.Now().Month <= 4) // Only send Feb, Mar, April
                            Global.InputErrors.Add(new Error(this, null, null, Error.Owner.ac, String.Format("\"{0}\" for {1} in CRM but not on Trello", AdmissionResult.SchoolName, AdmissionResult.StudentName)));
                }
            }

            // Check if there are no more than 5 schools (and no more than 2 from Rally 2 to 7)
            int SchoolInRally = 0;
            string SchoolListNames = "";
            for (int i = 2; i <= RallyHelper.NoOfRally; i++) // Rally 2 to 7
            {
                SchoolInRally = 0;
                SchoolListNames = "";

                for (int j = 0; j < MAX_SCHOOL_IN_RALLY; j++)
                {
                    if (RallyOfSchools[i][j] != null)
                    {
                        if (!RallyOfSchools[i][j].NonSuppliment)
                        {
                            SchoolInRally += 1;

                            if (i == RallyHelper.CurrentRally)
                                ApplicationStats.SchoolInCurrentRally += 1;

                            if (SchoolListNames != "")
                                SchoolListNames += ", ";
                            SchoolListNames += RallyOfSchools[i][j].School;
                        }
                    }
                }
            }

            ApplicationStats.ProgressScore = 0;
            ApplicationStats.TotalAssignedDraft = 0;
            ApplicationStats.TotalOverDuedDraft = 0;
            ApplicationStats.TotalPendingRevision = 0;
            ApplicationStats.TotalOverDuedRevision = 0;

            foreach (var School in Schools)
            {
                ApplicationStats.TotalAssignedDraft += School.SchoolStats.GetTotalAssignedDraft();
                ApplicationStats.TotalOverDuedDraft += School.SchoolStats.GetTotalOverDuedDraft();
                ApplicationStats.TotalPendingRevision += School.SchoolStats.GetTotalPendingRevision();
                ApplicationStats.TotalOverDuedRevision += School.SchoolStats.GetTotalOverDuedRevision();

                if (School.SchoolStats.NumberOfEssay != 0 && School.SchoolStats.RallyStatus > 0)
                {
                    if (School.SchoolStats.RallyStatus == 3) // Red = 0.5 but started
                        ApplicationStats.ProgressScore += 0.5;
                    else if (School.SchoolStats.RallyStatus == 2) // Yellow = 1
                        ApplicationStats.ProgressScore += 1.5;
                    else if (School.SchoolStats.RallyStatus == 1) // Green = 2
                        ApplicationStats.ProgressScore += 2;
                    else if (School.SchoolStats.RallyStatus == 4) // Mixed = 1 - treat as yellow
                        ApplicationStats.ProgressScore += 1;
                    else
                        ApplicationStats.ProgressScore += 0;
                }
            }
        }
    }
}
